from . import *
import DeviceSystem

def flatten_bases(cls, base):
    result = []
    current = cls
    while current != base and current != object:
        current = current.__bases__[0]
        result.append(current)
    return result

class MetaFactory(type):
    def __new__(cls, name, bases, dict):
        metabase = dict.get('meta_base')
        last_cls = DummyBase
        if metabase is not None:
            l = flatten_bases(bases[0], DummyBase)
            
            #c = l[len(l) - 2]
            #new_cls = type(c.__name__, (metabase, ), c.__dict__)
            l.reverse()
            
            for c in l:
                if c.__bases__[0] == last_cls:
                    if last_cls == DummyBase:
                        last_cls = type(c.__name__, (metabase, ), c.__dict__)
                    last_cls = type(c.__name__, (last_cls, ), c.__dict__)
    
            bob
        return type.__new__(cls, name, (last_cls, ), dict)

class DummyBase(object):
    pass
    


class NormalDevice(DummyBase):
    _saved_class_name = 'NormalDevice'
    uiTypeName = 'Normal'
    #__metaclass__ = MetaFactory
    def __init__(self, metacls, **kwargs):
        if hasattr(self, 'base_class') is False:
            self.base_class = metacls.__name__
        #metacls.__init__(self, **kwargs)
        super(self.__class__, self).__init__(**kwargs)

class PixelMappedDevice(DummyBase):
    _saved_class_name = 'PixelMappedDevice'
    _saved_attributes = ['grid_size', 'orientation']
    _saved_child_objects = ['pixels']
    uiTypeName = 'Pixel Mapped Device'
    def __init__(self, metacls, **kwargs):
        if hasattr(self, 'base_class') is False:
            self.base_class = metacls.__name__
        #metacls.__init__(self, **kwargs)
        super(self.__class__, self).__init__(**kwargs)
        self.check_dead_pixels(1)
        self.register_signal('grid_resized')
        self.register_signal('new_pixel')
        if hasattr(self, 'pixels_by_location') is False:
            self.pixels_by_location = {}
        if hasattr(self, 'pixels') is False:
            self.pixels = {}
        else:
            for pixel in self.pixels.itervalues():
                self.pixels_by_location.update({pixel.location:pixel})
        self.check_dead_pixels(2)
        if 'deserialize' not in kwargs:
            #self.grid_size = kwargs.get('grid_size', [1, 1])
            self.orientation = kwargs.get('orientation', 0)
            pixels = kwargs.get('pixels', None)
            if pixels is not None:
                for x, pixel in enumerate(pixels):
                    self.add_pixel(pixel)
                    self.check_dead_pixels(3, x)
            self.resize_grid(kwargs.get('grid_size', [1, 1]))
            self.check_dead_pixels(4)
#    def get_saved_attr(self, **kwargs):
#        print 'base intercepted'
#        self.check_dead_pixels('get_saved_attr')
#        d = super(PixelMappedDevice, self).get_saved_attr(**kwargs)
#        return d
    def check_dead_pixels(self, *args):
        if hasattr(self, 'pixels'):
            for key, val in self.pixels.iteritems():
                if val is None:
                    print 'dead pixel key=', key, 'args=',  args
                    return True
        return False
        
    def resize_grid(self, size):
        if hasattr(self, 'grid_size') is False:
            self.grid_size = [0, 0]
        for dim in range(2):
            if size[dim] is not None:
                if size[dim] < self.grid_size[dim]:
                    #remove existing pixels
                    pass
                elif size[dim] > self.grid_size[dim]:
                    self.grid_size[dim] = size[dim]
                    self.emit('grid_resized')
        for x in range(self.grid_size[0]):
            for y in range(self.grid_size[1]):
                if (x, y) not in self.pixels_by_location:
                    self.add_pixel(location=(x, y))
                    self.check_dead_pixels(5, (x, y))
    
    def add_pixel(self, **kwargs):
        '''
        :Parameters:
           'location' : tuple of x, y location indecies (used for dict key)
        '''
        location = kwargs.get('location')
        if self._check_size:
            new_kwargs = kwargs
            new_kwargs.update({'parent_device':self, 'osc_address':str(kwargs.get('location'))})
            self.add_child_object(**new_kwargs)
            #new_kwargs.update(self.add_osc_child(address=str(kwargs.get('location'))))
            factory = DeviceSystem.DeviceFactory()
            pixel = factory.make(type='Pixel', base=self.base_class, kwargs=new_kwargs)
            self.pixels.update({pixel.id:pixel})
            self.pixels_by_location.update({pixel.location:pixel})
            self.emit('new_pixel', location=location, id=pixel.id)
            print 'new_pixel'
    
    def _check_size(self, location):
        for x in range(2):
            if location[x] > self.grid_size[x]:
                return False
        return True
        
    def _deserialize_child(self, d):
        base_result = super(PixelMappedDevice, self)._deserialize_child(d)
        if base_result is not False:
            return base_result
        if hasattr(self, 'pixels') is False:
            self.pixels = {}
        if d['root_name'] == Pixel._saved_class_name:
            factory = DeviceSystem.DeviceFactory()
            d.update({'osc_address':str(d['attrs']['location'])})
            self.add_child_object(**d)
            pixel = factory.make_from_dict(d)
            if pixel is None:
                bob
            #self.pixels.update({pixel.location:pixel})
            if self.check_dead_pixels(6):
                bob
            return pixel

class ColorGroupRGB(DummyBase):
    _saved_class_name = 'ColorGroupRGB'
    _saved_attributes = ['color_map_keys', 'color_mode', 'parent_device_id']
    uiTypeName = 'RGB Color'
    color_keys = ('red', 'green', 'blue', 'white')
    def __init__(self, metacls, **kwargs):
        if hasattr(self, 'base_class') is False:
            self.base_class = metacls.__name__
        super(self.__class__, self).__init__(**kwargs)
        
        if 'deserialize' not in kwargs:
            self.parent_device = kwargs.get('parent_device')
            self.parent_device_id = self.parent_device.id
            self.color_mode = kwargs.get('color_mode', 'RGB')
            color_map = kwargs.get('color_map', None)
            if color_map is not None:
                for key, val in color_map.iteritems():
                    self.set_color_map(val)
            else:
                self.color_map = {}
        
        if hasattr(self, 'color_map_keys') is False:
            self.color_map_keys = {}
        if hasattr(self, 'color_map') is False:
            self.color_map = {}        
            for key, val in self.color_map_keys.iteritems():
                if key in self.Attributes:
                    self.color_map.update({key:self.Attributes[key]})
        
    def set_color_map(self, **kwargs):
        attribute = kwargs.get('attribute', None)
        if attribute is None:
            id = kwargs.get('attribute_id')
            attribute = self.Attributes[id]
        color = kwargs.get('color')
        self.color_map.update({color:attribute})
        self.color_map_keys.update({color:attribute.name})
    
    def add_attribute(self, **kwargs):
        attrib_name = kwargs.get('attribute').name
        super(self.__class__, self).add_attribute(**kwargs)
        color_name = kwargs.get('color_name', None)
        if color_name is not None:
            attribute = self.Attributes[attrib_name]
            self.set_color_map(attribute=attribute, color=color_name)
    
    def set_color(self, rgb):
        if self.color_mode == 'RGB':
            for x, val in enumerate(rgb):
                key = Pixel.color_keys[x]
                if key in self.color_map:
                    self.color_map[key].set_value(val)
        else:
            if 'white' in self.color_map:
                color_val = 0
                for val in rgb:
                    color_val += val
                color_val = color_val / 765
                self.color_map['white'].set_value(color_val)
                
    def _update_attributes(self):
        pass
        
class Pixel(ColorGroupRGB):
    '''Pixel
    :Parameters:
        'parent_device' : instance of the parent device
        'location' : tuple of x, y location of the pixel in the parent device
        'color_mode' : string (RGB, RGBW, etc) of color mode for the pixel
            (not used yet) default is RGB
        'color_map' : dictionary of color=attribute to map the color modes
            default is None
    '''
    _saved_class_name = 'Pixel'
    _saved_attributes = ['location']
    uiTypeName = 'Pixel'
    def __init__(self, metacls, **kwargs):
        if hasattr(self, 'base_class') is False:
            self.base_class = metacls.__name__
        #metacls.__init__(self, **kwargs)
        super(self.__class__, self).__init__(**kwargs)
        if 'deserialize' not in kwargs:
            self.location = kwargs.get('location')
        
        self.name = "row %s, col %s" % (self.location[1], self.location[0])
        #self.id = self.location

class BaseDeviceType(object):
    pass

class DefinedDeviceType(BaseDeviceType):
    pass

class PatchedDeviceType(DefinedDeviceType):
    pass
